1. Authorization
Being able to identify the
client is just half the process. Included in the security story for WCF
is authorization, which determines the access that is allowed to
various resources. This is related to granting access on the service
side. Three main elements affect the ability of a service to access
resources.
1.1. Process Identity
As you know by now, WCF
services run in a service host. This host runs in a process, either on
its own or combined with other hosts, and the process in which the host
is running has a security context, or process identity, that controls
the access rights accorded to the process.
You are probably
familiar with this concept when applied to ASP.NET. The host for
ASP.NET typically runs as a local user called ASP.NET. It is possible
for an administrator to change this user ID, but that’s a rare
occurrence, so when a Web page is executed (or, as it turns out, a WCF
service is hosted within Microsoft Internet Information Server [IIS]),
its access is restricted to whatever rights have been granted to the
ASP.NET user (normally, not very many rights, for security reasons).
1.2. Security Principal
Along with the process
identity, a security principal is attached to each executing thread.
The principal is a container for the caller’s identity and the roles
that are associated with it. The main difference between the process
identity and the security principal is the level of control that
is possible. A developer cannot change the process identity for a
running process. An element of impersonation is possible (and is
discussed later in this lesson), but the underlying process identity is
immutable.
In many cases, the principal
might be related to a Windows account, but this is not a requirement.
Developers can create a new security principal object, complete with
its own identity and set of roles. The principal object can then be
associated with a running thread. Because the principal contains not
just identity information but also the roles to which the user belongs,
this provides a mechanism for role-based authentication to be
implemented.
The mechanism through which the roles associated with a principal can be used to control access to a method uses the PrincipalPermissionAttribute.
If you are familiar with .NET permission coding (either imperative or
declarative), the pattern will not be new to you. In the declarative
form, the PrincipalPermissionAttribute is applied to the method in the class that implements the service’s contract:
' VB
<PrincipalPermission(SecurityAction.Demand, Role := "Updaters")> _
Public Function Update() As Boolean
Return True
End Function
// C#
[PrincipalPermission(SecurityAction.Demand, Role = "Updaters")]
public bool Update()
{
return true;
}
In this example, the
current principal is checked to see whether it belongs to a role called
Updaters. In the actual implementation of the attribute, the IsInRole method on the principal is called.
Note: If the PrincipalPermissionAttribute
is applied to the Service contract (as opposed to the method), an
exception is thrown. This attribute can be associated only with a
method.
For imperative determination of the PrincipalPermissionAttribute, an instance of the PrincipalPermission class is created. The constructor for PrincipalPermission takes the username and role as a parameter. When instantiated, the Demand
method can be called to determine whether the current principal has the
necessary permissions. The following code provides an example:
' VB
Dim p As New PrincipalPermission(Nothing, "Updaters")
p.Demand()
// C#
PrincipalPermission p = new PrincipalPermission(null, "Updaters");
p.Demand();
Note: The source for the principal used by the PrincipalPermission
class (or the attribute) is not important. It doesn’t matter whether
the principal is associated with a Windows user or was created by a
custom membership provider. All that matters is the result from the IsInRole call made while evaluating the permission.
1.3. ServiceSecurityContext
The ServiceSecurityContext
class provides run-time access to information about the security
context for a request. It might seem that this is basically the same
function as is performed by the security principal. However, this class
includes not just identity information but also a set of claims and
authorization policies. This additional information enables a much more
finely grained level of authorization. The next section discusses the
details of how this is accomplished.